import * as FilePond from 'filepond';
import zh_CN from 'filepond/locale/zh-cn.js';
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
import FilePondPluginFileValidateType from 'filepond-plugin-file-validate-type';
import FilePondPluginMediaPreview from 'filepond-plugin-media-preview';
import FilePondPluginGetFile from 'filepond-plugin-get-file';
import { setupFilelist } from '@/lib/file';
import type { File } from '@/lib/file';
import { getCsrfToken } from '@/lib/utils';

interface FileUploaderOptions {
    multiple?: boolean;
    maxFiles?: number;
    acceptedFileTypes?: string[];
    readonly?: boolean;
    instantUpload?: boolean;
    disableUploadButton?: boolean;
    disablePreview?: boolean;
}

type InitialFilesConfiguration = FilePond.FilePondServerConfigProps['files'];

export class FileUploader {
    public pond?: FilePond.FilePond;
    
    constructor(
        element: HTMLElement,
        initial_files: InitialFilesConfiguration,
        options: FileUploaderOptions = {}
    ) {
        if (options.readonly) {
            this.setupFilelist(element, initial_files);
        } else {
            this.setupFilepond(element, initial_files, options);
        }
    }

    private setupFilelist(
        element: HTMLElement,
        initial_files: InitialFilesConfiguration,
    ) {
        const files = initial_files?.map(file => {
            return {
                name: file.options.file.name,
                size: file.options.file.size,
                uploaded_at: file.options.metadata.uploaded_at,
                url: file.options.metadata.url,
                type: file.options.file.type,
            };
        });
        setupFilelist(element, files as File[]);
    }

    private setupFilepond(
        element: HTMLElement,
        initial_files: InitialFilesConfiguration,
        options: FileUploaderOptions = {}
    ) {
        // Register plugins
        FilePond.registerPlugin(FilePondPluginImagePreview);
        FilePond.registerPlugin(FilePondPluginFileValidateType);
        FilePond.registerPlugin(FilePondPluginMediaPreview);
        FilePond.registerPlugin(FilePondPluginGetFile);

        const chunk_size = 5000000  // must be less than settings.DATA_UPLOAD_MAX_MEMORY_SIZE
        
        // Create FilePond instance
        this.pond = FilePond.create(element, {
            ...zh_CN,
            labelFileTypeNotAllowed: "不支持此类型文件",
            fileValidateTypeLabelExpectedTypes: "支持 {allButLastType} 以及 {lastType} 文件类型",
            
            server: {
                url: '/media',
                process: {
                    url: '/upload/',
                    // @ts-ignore
                    headers: (file, _metadata) => {
                        return {
                            'Upload-Custom-Filename': encodeURIComponent(file.name),
                            'X-CSRFToken': getCsrfToken() || '',
                            ...(file.size > chunk_size && {
                                'Upload-Length': file.size
                            })
                        }
                    }
                },
                revert: {
                    url: '/upload/',
                    headers: {
                        'X-CSRFToken': getCsrfToken() || '',
                    }
                },
                restore: {
                    url: '/upload/',
                    headers: {
                        'X-CSRFToken': getCsrfToken() || '',
                    }
                },
                load: {
                    url: '/load/',
                    headers: {
                        'X-CSRFToken': getCsrfToken() || '',
                    }
                },
                fetch: null,
                patch: {
                    url: '/upload/',
                    headers: {
                        'X-CSRFToken': getCsrfToken() || '',
                    }
                }
            },
            chunkUploads: true,
            chunkSize: chunk_size,
            credits: false,
            maxFiles: options.maxFiles ?? null,
            instantUpload: options.instantUpload ?? true,
            allowMultiple: options.multiple,
            acceptedFileTypes: options.acceptedFileTypes,
            allowProcess: !(options.disableUploadButton ?? false),
            allowDownloadByUrl: true,
            files: initial_files,
            allowImagePreview: !(options.disablePreview ?? false),
            allowVideoPreview: !(options.disablePreview ?? false),
            allowAudioPreview: !(options.disablePreview ?? false)
        });
    }
}

export function setupFileUploadFormFields() {
    document.querySelectorAll('[data-file-uploader]').forEach(elem => {
        const raw_value = (elem as HTMLInputElement).value
        
        var initial_files: InitialFilesConfiguration = []
        if (raw_value) {
            initial_files = JSON.parse((elem as HTMLInputElement).value)
        }
        
        new FileUploader(elem as HTMLElement, initial_files, {
            multiple: (elem as HTMLElement).dataset.multiple === 'true',
            readonly: (elem as HTMLInputElement).disabled,
            acceptedFileTypes: (elem as HTMLElement).dataset.allowedTypes?.split(" ").filter(Boolean) ?? []
        });
    });
}
